﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using BankCreditPortfolio.DAL;
using BankCreditPortfolio.DAL.Entities;
using BankCreditPortfolio.DAL.Services;

namespace BankCreditPortfolio.Models.AccountModels
{
    public class RegisterModel : IBaseModel<Client>
    {
        [Required, StringLength(40)]
        [Display(Name = "First name")]
        [RegularExpression(@"^ *([A-Z][a-z]*[\s-']?)*([A-Z][a-z]*)+ *$", ErrorMessage = "The {0} is incorrect.")]
        public string FirstName { get; set; }

        [Required, StringLength(40)]
        [Display(Name = "Last name")]
        [RegularExpression(@"^ *([A-Z][a-z]*[\s-']?)*([A-Z][a-z]*)+ *$", ErrorMessage = "The {0} is incorrect.")]
        public string LastName { get; set; }

        [Required, StringLength(40)]
        [Display(Name = "Middle name")]
        [RegularExpression(@"^ *([A-Z][a-z]*[\s-']?)*([A-Z][a-z]*)+ *$", ErrorMessage = "The {0} is incorrect.")]
        public string MiddleName { get; set; }

        [Required, StringLength(255)]
        [DataType(DataType.EmailAddress)]
        [RegularExpression(@"^ *[-a-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|[a-z][a-z]) *$", ErrorMessage = "This e-mail is not correct.")]
        [Display(Name = "Email address")]
        public string Email { get; set; }

        [Required]
        [StringLength(14, ErrorMessage = "The {0} must be {2} characters long.", MinimumLength = 14)]
        [RegularExpression(@"^ *[0-9]{7}[a-zA-Z][0-9]{3}[a-zA-Z]{2}[0-9] *$", ErrorMessage = "The {0} is in incorrect format.")]
        [Display(Name = "Passport Personal Number")]
        public string PersonalId { get; set; }

        [Required]
        [DataType(DataType.Date)]
        [DisplayFormat(NullDisplayText = "", DataFormatString = "{0:MM/dd/yyyy}")]
        [RegularExpression(@"^([1-9]|0[1-9]|1[012])/([1-9]|0[1-9]|[12][0-9]|3[01])/[0-9]{4}$", ErrorMessage = "The {0} is incorrectly formatted. Right format: MM/DD/YYYY.")]
        [Display(Name = "Date of passport delivery")]
        public string PassportDate { get; set; }

        [Required, StringLength(255, MinimumLength = 4)]
        [Display(Name = "Passport issuing authority")]
        public string PassportIssuingAuthority { get; set; }

        [Required, StringLength(255, MinimumLength = 4)]
        [Display(Name = "Address")]
        public string Address { get; set; }

        [Required]
        [DataType(DataType.PhoneNumber)]
        [Display(Name = "Phone")]
        [RegularExpression(@"^ *\+[0-9]{5} [0-9]{7} *$", ErrorMessage = "The {0} is not in international format (+XXXXX XXXXXXX).")]
        public string Phone { get; set; }

        [Required, StringLength(255, MinimumLength = 4)]
        [Display(Name = "Workplace")]
        public string Workplace { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 8)]
        [DataType(DataType.Password)]
        [RegularExpression(@"^ *.*(?=.*\d)(?=.*[A-Za-z]).* *$", ErrorMessage = "The {0} must contain at least 1 latin symbol and 1 number.")]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var accountService = new AccountService();
            if (accountService.GetByEmail(Email) != null)
            {
                yield return
                    new ValidationResult("The e-mail address already exists. Please enter a different e-mail address.",
                                         new[] { "Email" });
            }

            DateTime date;
            if (!DateTime.TryParse(PassportDate, CultureInfo.CreateSpecificCulture("en-US"), DateTimeStyles.None, out date))
            {
                yield return new ValidationResult("The passport delivery date is incorrect. Format: MM/DD/YYYY.",
                    new[] { "PassportDate" });
            }
            else
            {
                var minDate = DateTime.Today.AddYears(-10);
                var maxDate = DateTime.Today;

                if (date < minDate || date > maxDate)
                {
                    yield return new ValidationResult(String.Format("The passport delivery date must be between {0} and {1}.",
                        minDate.ToShortDateString(), maxDate.ToShortDateString()),
                        new[] { "PassportDate" });
                }
            }
        }

        public IBaseModel<Client> MapFrom(Client @from)
        {
            throw new NotImplementedException();
        }

        public Client MapTo(Client to)
        {
            var accountService = new AccountService();
            var roleService = new RoleService();

            var passwordHash = PasswordHelper.Encrypt(Password, PasswordMode.MD5);
            var account = new Account
            {
                Email = Email,
                Hash = passwordHash.Hash,
                Salt = passwordHash.Salt,
                Role = roleService.GetRoleByTitle("Client")
            };

            var profileService = new ProfileService();
            var profile = new Profile
            {
                Adress = Address,
                Phone = Phone,
                FirstName = FirstName,
                LastName = LastName,
                MiddleName = MiddleName,
                PassportIssuingAuthority = PassportIssuingAuthority,
                PassportDate = DateTime.Parse(PassportDate),
                PersonalId = PersonalId,
                Work = Workplace
            };

            var clientService = new ClientService();
            var client = new Client
            {
                Account = account,
                Profile = profile
            };

            try
            {
                accountService.Save(ref account);
                profileService.Save(ref profile);
                clientService.Save(ref client);
                return client;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}